package org.jeecg.modules.system.controller;

import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.binarywang.wxpay.bean.payscore.*;
import com.github.binarywang.wxpay.bean.request.WxPayPartnerRefundV3Request;
import com.github.binarywang.wxpay.bean.request.WxPayRefundV3Request;
import com.github.binarywang.wxpay.bean.result.WxPayRefundV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.system.entity.DeviceInfo;
import org.jeecg.modules.system.entity.OrderInfo;
import org.jeecg.modules.system.entity.SettingInfo;
import org.jeecg.modules.system.service.IDeviceInfoService;
import org.jeecg.modules.system.service.IOrderInfoService;
import org.jeecg.modules.system.service.ISettingInfoService;
import org.jeecg.modules.system.service.IWxPayScoreService;
import org.jeecg.modules.system.vo.OrderInfoVO;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;


/**
 * @author Binary Wang
 */
@Api("微信支付分")
@RestController
@RequestMapping("/wx/payScore")
@AllArgsConstructor
@Slf4j
public class WxPayScoreController {
    private WxPayService wxService;

    @Resource
    private IOrderInfoService orderInfoService;

//    @Resource
//    private ISettingInfoService settingInfoService;

    @Resource
    private IDeviceInfoService deviceInfoService;

    @Resource
    private IWxPayScoreService wxPayScoreService;

    @Resource
    private RedisUtil redisUtil;

    @Resource
    private ISettingInfoService settingInfoService;

//    @Autowired
//    private RedisTemplate<String, Object> redisTemplate;


    /**
     * 验证用户是否签约支付分
     */
    @GetMapping("/signCheck")
    public void signCheck(@RequestParam(name = "openId") String openId) {
        try {
            WxPayScoreResult wxPayScoreResult = wxService.getPayScoreService().permissionsQueryByOpenId(openId);

            log.info("验证签约结果为：{}", wxPayScoreResult);
        } catch (WxPayException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建微信支付分订单
     *
     * @return
     */
    @GetMapping("/createOrder")
    public Result createOrder(@RequestParam(name = "openId") String openId) {
        WxPayScoreRequest wxPayScoreRequest = new WxPayScoreRequest();
        wxPayScoreRequest.setOutOrderNo(getOutTradeNo());
        wxPayScoreRequest.setServiceIntroduction("停车位租借");
        List<PostPayment> postPaymentList = new ArrayList<>();
        PostPayment postPayment = new PostPayment();
        postPayment.setName("收费标准");
        SettingInfo settingInfo = settingInfoService.getById(1);
        BigDecimal hourFee = new BigDecimal(settingInfo.getHourFee());
        BigDecimal fixedFee = new BigDecimal(settingInfo.getFixedFee());
        BigDecimal h = hourFee.divide(new BigDecimal("100"));
        BigDecimal f = fixedFee.divide(new BigDecimal("100"));
        postPayment.setDescription(h+"元/小时，"+f+"元封顶。");
        postPaymentList.add(postPayment);
        wxPayScoreRequest.setPostPayments(postPaymentList);
        RiskFund riskFund = new RiskFund();
        riskFund.setName("ESTIMATE_ORDER_COST");
        riskFund.setAmount(10);
        wxPayScoreRequest.setRiskFund(riskFund);
        wxPayScoreRequest.setAttach(wxService.getConfig().getMchId());
        wxPayScoreRequest.setNotifyUrl("https://www.sqzxxny.top/zxds/callback/dky/chargeStatus");
        wxPayScoreRequest.setOpenid(openId);
        wxPayScoreRequest.setNeedUserConfirm(true);
        try {
            //订单开始时间为10秒后
            TimeRange timeRange = new TimeRange();
            DateTime dateTime = DateUtil.offsetSecond(DateUtil.date(), 10);
            timeRange.setStartTime(DateUtil.format(dateTime, "yyyyMMddHHmmss"));
            wxPayScoreRequest.setTimeRange(timeRange);
            WxPayScoreResult serviceOrder = wxService.getPayScoreService().createServiceOrder(wxPayScoreRequest);
            log.info("serviceOrder:{}", serviceOrder);
            return Result.OK(serviceOrder);
        } catch (WxPayException e) {
            e.printStackTrace();
            return Result.error(e.getMessage());
        }
    }

    /**
     * 支付分查询订单API.
     *
     * @param queryId
     * @return
     */
    @GetMapping("/queryServiceOrder")
    public Result queryServiceOrder(String queryId) {
        log.info("queryId:{}",queryId);
        if (StringUtils.isBlank(queryId) || "undefined".equals(queryId)){
            return Result.error("用户取消操作");
        }
        try {
            WxPayScoreResult wxPayScoreResult = wxService.getPayScoreService().queryServiceOrder(null, queryId);
            log.info("queryServiceOrder:{}", wxPayScoreResult);
            String outOrderNo = wxPayScoreResult.getOutOrderNo();
            OrderInfo one = orderInfoService.getOne(Wrappers.<OrderInfo>lambdaQuery()
                    .eq(OrderInfo::getOutTradeNo, outOrderNo)
            );
            if(null!=one){
                Integer checkStatus = one.getCheckStatus();
                if(checkStatus==1){
                    return Result.error(201,"已验证");
                }
            }
            return Result.OK();
        } catch (WxPayException e) {
            e.printStackTrace();
            return Result.error(e.getMessage());
        }
    }

    /**
     * 支付分取消订单
     *
     * @return
     */
    @PostMapping("/cancelServiceOrder")
    public Result cancelServiceOrder(@RequestBody JSONObject data) {
//        outTradeNo = "2024041319552862800001";
        LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        if("1".equals(sysUser.getClientId())){
            try {
                OrderInfo orderInfo=null;
                String outTradeNo = data.getString("outTradeNo");
                try {
                    orderInfo = orderInfoService.getOne(Wrappers.<OrderInfo>lambdaQuery()
                            .eq(OrderInfo::getOutTradeNo, outTradeNo)
                    );
                } catch (Exception e) {
                    e.printStackTrace();
                    return Result.error(e.getMessage());
                }
                WxPayScoreResult wxPayScoreResult = wxService.getPayScoreService().queryServiceOrder(outTradeNo, null);
                WxPayRefundV3Request wxPayRefundV3Request = new WxPayPartnerRefundV3Request();
//                wxPayRefundV3Request.setOutTradeNo(outTradeNo);
                wxPayRefundV3Request.setOutRefundNo("9"+outTradeNo);
                wxPayRefundV3Request.setTransactionId(wxPayScoreResult.getCollection().getDetails().get(0).getTransactionId());
                WxPayRefundV3Request.Amount amount = new WxPayRefundV3Request.Amount();
                amount.setTotal(Integer.valueOf(orderInfo.getTotalFee()));
                amount.setRefund(Integer.valueOf(orderInfo.getTotalFee()));
                amount.setCurrency("CNY");
                wxPayRefundV3Request.setAmount(amount);
                WxPayRefundV3Result wxPayRefundV3Result = wxService.refundV3(wxPayRefundV3Request);
                log.info("wxPayRefundV3Result:{}", wxPayRefundV3Result);
                orderInfo.setRefundFlag(1);
                orderInfoService.updateById(orderInfo);
                return Result.OK(wxPayRefundV3Result);
            } catch (WxPayException e) {
                e.printStackTrace();
                return Result.error(e.getMessage());
            }
        }else{
            return Result.error("无权限");
        }

    }

    /**
     * 小程序扫码校验地锁信息
     */
    @GetMapping("/checkDevice")
    public Result checkDevice(@RequestParam(name = "deviceNo") String deviceNo) {
        DeviceInfo one = deviceInfoService.getOne(Wrappers.<DeviceInfo>lambdaQuery()
                .eq(DeviceInfo::getDeviceNo, deviceNo)
        );
        if (null != one) {
            Integer onlineState = one.getOnlineState();
            Integer lockState = one.getLockState();
            Integer parkingState = one.getParkingState();
            if (onlineState == 0) {
                return Result.error("设备离线无法使用");
            }
            if (lockState == 2) {
                return Result.error("设备已落锁，无法使用");
            }
            if (parkingState == 1) {
                return Result.error("车位有车，无法使用");
            }
        } else {
            return Result.error("设备不存在");
        }
        String addressInfo = one.getStationName()+one.getZhuangName()+one.getQiangName();
        return Result.OK(addressInfo);
    }

    /**
     * 控制车锁设备
     * @param data
     * @return
     */
    @PostMapping("/control")
    public Result controlDevice(@RequestBody JSONObject data){
        return wxPayScoreService.controlDevice(data);
//        String deviceNo = data.getString("deviceNo");
//        String outOrderNo = data.getString("outOrderNo");
//        if(org.apache.commons.lang3.StringUtils.isAnyBlank(deviceNo,outOrderNo)){
//            return Result.error("请求信息异常，请重新扫码操作");
//        }
//        try {
//            WxPayScoreResult wxPayScoreResult = wxService.getPayScoreService().queryServiceOrder(outOrderNo, null);
//            log.info("queryServiceOrder:{}", wxPayScoreResult);
//            String openid = wxPayScoreResult.getOpenid();
//            String startTimeStr = wxPayScoreResult.getTimeRange().getStartTime();
//            DateTime startTime = DateUtil.parse(startTimeStr);
////            表示当前单据状态
////            枚举值：
////            CREATED：商户已创建服务订单；
////            DOING：服务订单进行中；
////            DONE：服务订单完成；
////            REVOKED：商户取消服务订单；
////            EXPIRED：服务订单已失效，"商户已创建服务订单"状态超过30天未变动，则订单失效
//            String state = wxPayScoreResult.getState();
//            OrderInfo orderInfo = new OrderInfo();
//            orderInfo.setOpenId(openid);
//            orderInfo.setOutTradeNo(outOrderNo);
//            orderInfo.setDeviceNo(deviceNo);
//            orderInfo.setStartTime(startTime);
//            orderInfo.setState(state);
//            //落锁
//            Result control = deviceInfoService.control(deviceNo, 2);
//            if(control.isSuccess()){
//                orderInfoService.save(orderInfo);
//                return Result.OK();
//            }else{
//                wxService.getPayScoreService().cancelServiceOrder(outOrderNo, control.getMessage()+"-订单取消");
//                return control;
//            }
//        } catch (WxPayException e) {
//            e.printStackTrace();
//            return Result.error(e.getMessage());
//        }

    }

    /**
     * 获取订单详情
     * @param outOrderNo
     * @return
     */
    @GetMapping("/getOrderDetail")
    public Result getOrderDetail(@RequestParam(name="outOrderNo") String outOrderNo){
        try {
            OrderInfo one = orderInfoService.getOne(Wrappers.<OrderInfo>lambdaQuery()
                    .eq(OrderInfo::getOutTradeNo, outOrderNo)
            );
            if (null==one){
                return Result.error("订单异常，请联系客服");
            }
            String state = one.getState();
            WxPayScoreResult wxPayScoreResult = wxService.getPayScoreService().queryServiceOrder(outOrderNo, null);
            one.setState(wxPayScoreResult.getState());
            OrderInfoVO orderInfoVO = new OrderInfoVO();
            BeanUtils.copyProperties(one,orderInfoVO);
            String formatBetween = DateUtil.formatBetween(orderInfoVO.getStartTime(),null==orderInfoVO.getEndTime()? DateUtils.getDate() :orderInfoVO.getEndTime(), BetweenFormatter.Level.MINUTE);
            orderInfoVO.setBetweenTime(formatBetween);
            DeviceInfo one1 = deviceInfoService.getOne(Wrappers.<DeviceInfo>lambdaQuery()
                    .eq(DeviceInfo::getDeviceNo, orderInfoVO.getDeviceNo())
            );
            if(null!=one1){
                orderInfoVO.setDeviceAddr(one1.getStationName()+one1.getZhuangName()+one1.getQiangName());
            }
            if (!wxPayScoreResult.getState().equals(state)){
                orderInfoService.updateById(one);
            }
            return Result.OK(orderInfoVO);
        } catch (WxPayException e) {
            e.printStackTrace();
            return Result.error(e.getMessage());
        }

    }

    private synchronized String getOutTradeNo() {
        String today = DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_MS_FORMAT);
        String formattedNumber = String.format("%05d", 1);
        return today + formattedNumber;
    }

}

